<?php

namespace app\common\exception;

use think\db\exception\DataNotFoundException;
use think\db\exception\ModelNotFoundException;
use think\exception\Handle;
use think\exception\HttpException;
use think\exception\HttpResponseException;
use think\exception\ValidateException;
use think\Response;
use ParseError;
use ReflectionException;
use RuntimeException;
use think\db\exception\PDOException;
use think\exception\ErrorException;
use think\facade\Env;
use Throwable;


/**
 * 应用异常处理类
 */
class Handler extends Handle
{
    private $status  = 0;
    private $message = '';
    private $msg     = '';

    /**
     * 不需要记录信息（日志）的异常类列表
     * @var array
     */
    protected $ignoreReport = [
        HttpException::class,
        HttpResponseException::class,
        ModelNotFoundException::class,
        DataNotFoundException::class,
        ValidateException::class,
    ];

    /**
     * 记录异常信息（包括日志或者其它方式记录）
     *
     * @access public
     * @param  Throwable $exception
     * @return void
     */
    public function report(Throwable $exception): void
    {
        // 使用内置的方式记录异常日志
        parent::report($exception);
    }

    /**
     * 定义异常状态
     *
     * @access public
     * @param \think\Request   $request
     * @param Throwable $e
     * @return Response
     */
    private function setErrorException($e)
    {
        if ($e instanceof ParseError) {
            //代码语法错误

            $this->status  = Status::Parse_Error;
            $this->message = Message::Parse_Error;
            $this->msg = $e->getMessage();
        } else if ($e instanceof ReflectionException) {
            //服务器异常映射

            $this->status  = Status::Reflection_Exception;
            $this->message = Message::Reflection_Exception;
            $this->msg = $e->getMessage();
        } else if ($e instanceof RuntimeException) {
            //服务器运行期异常

            $this->status  = Status::Run_Time_Exception;
            $this->message = Message::Run_Time_Exception;
            $this->msg = $e->getMessage();
        } else if ($e instanceof ErrorException) {
            //框架运行错误

            $this->status  = Status::Error_Exception;
            $this->message = Message::Error_Exception;
            $this->msg = $e->getMessage();
        } else if ($e instanceof ModelNotFoundException) {
            //数据库模型错误

            $this->status  = Status::Model_Not_Found_Exception;
            $this->message = Message::Model_Not_Found_Exception;
            $this->msg = $e->getModel();
        } else if ($e instanceof PDOException) {
            //数据库链接错误

            $this->status  = Status::PDO_Exception;
            $this->message = Message::PDO_Exception;
            $this->msg = $e->getMessage();
        }
    }

    /**
     * Render an exception into an HTTP response.
     *
     * @access public
     * @param \think\Request   $request
     * @param Throwable $e
     * @return Response
     */
    public function render($request, Throwable $e): Response
    {
        // 添加自定义异常处理机制

        //判断在`.env`里面是否开始了调试，开启了调试就原样返回，关闭了调试就返回自定义的json格式的错误信息
        if (Env::get('APP_DEBUG') == 1) {
            return parent::render($request, $e);
        }

        $this->setErrorException($e);
        if ($this->status) {
            $result = [
                'file'    => $e->getFile(),
                'line'    => $e->getLine(),
                'message' => $this->msg
            ];
            return json([
                'status'  => $this->status,
                'message' => $this->message,
                'data'    => $result
            ], Code::INTERNAL_SERVER_ERROR);
        }
        if ($e instanceof Exception) {
            $result = [
                'status'  => $e->getCode(),
                'message' => $e->getMessage()
            ];
            return json($result, Code::BAD_REQUEST);
        }
        // 其他错误交给系统处理
        return parent::render($request, $e);
    }
}
